home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
smaltalk
/
manchest.lha
/
MANCHESTER
/
usenet
/
st80_pre4
/
3state-buttons.st
< prev
next >
Wrap
Text File
|
1993-07-24
|
15KB
|
509 lines
" NAME 3state-buttons
AUTHOR ross@prls.UUCP (Ross Morley)
FUNCTION a SwitchView with three states
ST-VERSIONS 2.3
PREREQUISITES
CONFLICTS
DISTRIBUTION world
VERSION 1.1
DATE 31 Aug 90
SUMMARY A pluggable switch view with three states (black, grey and
white) and two ways to press it (click or prolonged press).
"
!
"
Newsgroups: comp.lang.smalltalk
Subject: tri-state button goody
Keywords: goody goodies switch pluggable
Message-ID: <43407@prls.UUCP>
Date: 31 Aug 90 21:42:16 GMT
Organization: Philips R&D Center, Sunnyvale, CA
Here's a little goody which many of you may find useful.
It's a SwitchView with three states (black, grey and white) and two ways
to press it (click or prolonged press). It can be plugged into your
application very easily (see examples included) by defining three simple
messages in your application class that is to be its model. You can name
the messages as you like - simply tell the TriStateButtonView what they
are called when you plug it in. The corresponding methods in your model
class determine the semantics of the button: which color it is, and the
effects of clicking or pressing it. I have included a contrived example
application with two TriStateButtons with different semantics, so you can
play with them as soon as you file this in.
Ross P. Morley pyramid!!prls!!ross
Philips Research, Sunnyvale philabs!!prls!!ross
811 E. Arques Ave (MS02) ross@prls.uucp
Sunnyvale, CA 94088-3409 Tel. (408) 991 5057
"
'From Smalltalk-80, Version 2.3 of 13 June 1988 on 31 August 1990 at 12:11:57 pm'!
SwitchView subclass: #TriStateButtonView
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Interface-VisualControls'!
TriStateButtonView comment:
'I am a pluggable tri-state button. I can display white, black or grey depending on the state of
my aspect in the model. My controller senses two kinds of events, a click and a prolonged press,
and signals the model accordingly. Some interfacing methods must be built into the model - see
comments on instance creation methods.
Copyright (C) 1990, Ross P. Morley.
This program is placed in the public domain. You may use and alter this program freely
for non-commercial purposes as long as you leave this message intact. Neither I nor
my company will recognize any responsibility for damages arising from use of this program.
'!
!TriStateButtonView methodsFor: 'controller access'!
defaultControllerClass
^TriStateButtonController! !
!TriStateButtonView methodsFor: 'deEmphasizing'!
deEmphasizeView
"Redisplay without emphasis."
emphasisOn _ false.
self displayView!
emphasizeView
"Redisplay with emphasis."
emphasisOn _ true.
self displayView! !
!TriStateButtonView methodsFor: 'displaying'!
displayLabelClippingBox: aRectangle rule: ruleInteger mask: maskInteger
"Display the label in the specified manner."
| center |
label isNil ifTrue: [^self].
center _ label boundingBox center.
label displayOn: Display
at: (label offset + (self displayTransformation applyTo: center) - center) rounded
clippingBox: aRectangle
rule: ruleInteger
mask: maskInteger!
displayView
"Interrogate the model and display the receiver accordingly."
| box0 box1 box2 state |
box0 _ self insetDisplayBox.
box1 _ box0 insetBy: 1.
box2 _ box1 insetBy: 1.
Display white: box0.
state _ self interrogateModel. "#white, #grey or #black"
state == #grey ifTrue: [Display veryLightGray: box0].
state == #black ifTrue: [Display black: box1].
emphasisOn
ifFalse: [
Display white: box2.
self displayLabelClippingBox: box2 rule: Form under mask: Form black]
ifTrue: [
state == #black
ifTrue: [self displayLabelClippingBox: box2 rule: Form erase mask: Form black]
ifFalse: [self displayLabelClippingBox: box2 rule: Form under mask: Form black]]! !
!TriStateButtonView methodsFor: 'initialize-release'!
initialize
super initialize.
selector _ #white! !
!TriStateButtonView methodsFor: 'selector'!
interrogateModel
"Send the selector message to the model to obtain the state of the aspect of the model
the receiver indicates. Answer the result (a Symbol: #black, #grey or #white)."
^model perform: selector! !
!TriStateButtonView methodsFor: 'updating'!
update: aspectSymbol
"The model has changed in aspect 'aspectSymbol'. If this is the receiver's aspect, redisplay."
aspectSymbol == selector ifTrue: [self display]! !
TriStateButtonView class
instanceVariableNames: ''!
!TriStateButtonView class methodsFor: 'instance creation'!
on: model aspect: aspectSymbol label: labelString click: clickSymbol press: pressSymbol
"Create a pluggable tri-state button on an aspect of model, where:
aspectSymbol is the selector sent to the model to get the current status which must
be #black, #grey or #white;
label is the label on the button;
clickSymbol is the selector sent to the model when the user clicks the button;
pressSymbol is the selector sent to the model when the user presses the button
and holds it for a predefined time."
| view |
(view _ self new)
model: model;
selector: aspectSymbol;
label: labelString asParagraph.
view controller
clickSelector: clickSymbol;
pressSelector: pressSymbol.
^view! !
!TriStateButtonView class methodsFor: 'examples'!
bothSwitches
TriStateButtonExample bothSwitches!
stateSwitch
TriStateButtonExample stateSwitch!
thisAndThatSwitch
TriStateButtonExample thisAndThatSwitch! !
SwitchController subclass: #TriStateButtonController
instanceVariableNames: 'pressSelector downTime pressed '
classVariableNames: ''
poolDictionaries: ''
category: 'Interface-VisualControls'!
TriStateButtonController comment:
'I work with TriStateButtonView. I sense two kinds of events, a click and a prolonged press,
and signal my model accordingly. The minimum duration of a press is defined by my class method
pressTime.
Instance Variables:
selector The selector I send for a click. A Symbol. This variable is defined in my superclass.
pressSelector The selector I send for a press (button held for a preset time).
downTime The absolute time (from the millisecond clock) when the mouse button was pressed.
pressed A Boolean indicating that a press event has occurred (button down timed out).
Copyright (C) 1990, Ross P. Morley.
This program is placed in the public domain. You may use and alter this program freely
for non-commercial purposes as long as you leave this message intact. Neither I nor
my company will recognize any responsibility for damages arising from use of this program.
'!
!TriStateButtonController methodsFor: 'accessing'!
clickSelector
"Answer the selector the receiver sends to its model when the user clicks on it
(a Symbol, or nil if none)."
^selector!
clickSelector: aSymbolOrNil
"Set the selector the receiver sends to its model when the clicks on it.
If nil, nothing is sent."
selector _ aSymbolOrNil!
downTime
"Recall the absolute time (from the millisecond clock) when the red button was pressed."
^downTime!
pressSelector
"Answer the selector the receiver sends to its model when the user presses it
for at least a preset length of time (a Symbol, or nil if none)."
^pressSelector!
pressSelector: aSymbolOrNil
"Set the selector the receiver sends to its model when the user presses it for.
a preset length of time. If nil, nothing is sent."
pressSelector _ aSymbolOrNil! !
!TriStateButtonController methodsFor: 'basic control sequence'!
controlInitialize
"The red button has gone down on the receiver. Begin timing it."
view indicatorReverse.
self markDownTime;
clearPressed!
controlTerminate
"The red button has been released. If not pressed send a click event. Relinquish control."
self hasBeenPressed ifTrue: [^self].
view indicatorReverse.
self sendClick! !
!TriStateButtonController methodsFor: 'control defaults'!
controlActivity
"Called repeatedly as long as a button is held. Check how long the button has been down
and, if long enough, generate a press event. After a press event has been generated, do
nothing (control is retained until the button is released)."
self hasBeenPressed ifTrue: [^self].
Time millisecondClockValue - self downTime > self class pressTime
ifTrue: [
view indicatorReverse.
self setPressed;
sendPress]!
isControlActive
"Answer whether the receiver still wants control. True as long as a mouse button is held."
^sensor anyButtonPressed!
isControlWanted
"Answer whether the receiver initially wants control. Override the superclass to avoid
setting the cursor because it is never restored (SwitchController bug)."
^self viewHasCursor & sensor redButtonPressed! !
!TriStateButtonController methodsFor: 'initialize-release'!
initialize
super initialize.
self clickSelector: #click;
pressSelector: #press;
markDownTime;
clearPressed! !
!TriStateButtonController methodsFor: 'private'!
clearPressed
pressed _ false!
hasBeenPressed
^pressed!
markDownTime
"Record the absolute time from the millisecond clock. Done when the red button is pressed."
downTime _ Time millisecondClockValue!
sendClick
"Send a click event to the model, if it wants it."
self clickSelector notNil
ifTrue: [model perform: self clickSelector]!
sendPress
"Send a press event to the model, if it wants it."
self pressSelector notNil
ifTrue: [model perform: self pressSelector]!
setPressed
pressed _ true! !
TriStateButtonController class
instanceVariableNames: ''!
!TriStateButtonController class methodsFor: 'defaults'!
pressTime
"Answer the length of time (ms) the button must be held down to be considered pressed.
If released before this time it is considered to have been clicked. An Integer."
^1200! !
Model subclass: #TriStateButtonExample
instanceVariableNames: 'state thisIs thatIs '
classVariableNames: ''
poolDictionaries: ''
category: 'Interface-VisualControls'!
TriStateButtonExample comment:
'This class exists to demonstrate TriStateButtons. It is not intended to be used itself in an
application, but merely to show how to interface a TriStateButtonView/Controller to an
application. It actually contains interfaces to two independent aspects which can be
indicated and controlled by tri-state buttons. Only the "interface" instance protocols
need to be provided in your application class. The example class methods can be executed
to show tri-state buttons in action.
Instance Variables:
state A Symbol (#yes, #no or #maybe).
thisIs A Boolean.
thatIs A Boolean.'!
!TriStateButtonExample methodsFor: 'accessing'!
state
"Answer the current state (a Symbol: #yes, #no or #maybe)."
^state!
state: aSymbol
"Set the current state (#yes, #no or #maybe)."
state _ aSymbol!
thatIs
"Answer whether that is true."
^thatIs!
thatIs: aBoolean
thatIs _ aBoolean!
thisIs
"Answer whether this is true."
^thisIs!
thisIs: aBoolean
thisIs _ aBoolean! !
!TriStateButtonExample methodsFor: 'initialize-release'!
initialize
state _ #maybe.
thisIs _ thatIs _ false! !
!TriStateButtonExample methodsFor: 'interface - state'!
stateSwitchClick
"The 'state' switch has been clicked. Respond to it and notify the TriStateSwitchView
(a dependent) of the change. Click toggles between yes and no states, but has no effect
in a maybe state."
self state == #maybe ifTrue: [^self].
self state == #yes
ifTrue: [self state: #no]
ifFalse: [self state: #yes].
self changed: #stateSwitchState!
stateSwitchPress
"The 'state' switch has been pressed. Respond to it and notify the TriStateSwitchView
(a dependent) of the change. Press changes to the maybe state from yes or no, or to the
no state from maybe (spoils the symmetry, but better have some way out of maybe!!)."
self state == #maybe
ifTrue: [self state: #no]
ifFalse: [self state: #maybe].
self changed: #stateSwitchState!
stateSwitchState
"Answer the state the tri-state switch should be in for the present state
(a Symbol: #black, #grey or #white)."
self state == #yes ifTrue: [^#black].
self state == #no ifTrue: [^#white].
^#grey! !
!TriStateButtonExample methodsFor: 'interface - this & that'!
thisAndThatSwitchClick
"The 'this & that' switch has been clicked. If this is then toggle that, otherwise that is
irrelevant so remember its previous state and (as a shortcut) set this.
Notify the TriStateSwitchView (a dependent) of the change."
self thisIs
ifTrue: [self thatIs: self thatIs not]
ifFalse: [self thisIs: true].
self changed: #thisAndThatSwitchState!
thisAndThatSwitchPress
"The 'this & that' switch has been pressed. Toggle this.
Notify the TriStateSwitchView (a dependent) of the change."
self
thisIs: self thisIs not;
changed: #thisAndThatSwitchState!
thisAndThatSwitchState
"Answer the state the tri-state switch should be in according to this and that
(a Symbol: #black, #grey or #white)."
self thisIs
ifTrue: [self thatIs
ifTrue: [^#black] "this is and that is"
ifFalse: [^#grey] "this is but that isn't"
]
ifFalse: [^#white] "this isn't and don't care about that"! !
TriStateButtonExample class
instanceVariableNames: ''!
!TriStateButtonExample class methodsFor: 'instance creation'!
new
^super new initialize! !
!TriStateButtonExample class methodsFor: 'examples'!
bothSwitches
"Open a window with two TriStateSwitchViews."
"TriStateButtonExample bothSwitches"
| model sSwitch ttSwitch topView |
model _ self new.
sSwitch _ TriStateButtonView on: model
aspect: #stateSwitchState
label: 'State'
click: #stateSwitchClick
press: #stateSwitchPress.
ttSwitch _ TriStateButtonView on: model
aspect: #thisAndThatSwitchState
label: 'This & That'
click: #thisAndThatSwitchClick
press: #thisAndThatSwitchPress.
(topView _ StandardSystemView new)
model: model;
minimumSize: 100@80;
borderWidth: 1;
addSubView: sSwitch in: (0@0 corner: 1.0@0.5) borderWidth: 1;
addSubView: ttSwitch in: (0@0.5 corner: 1.0@1.0) borderWidth: 1.
topView controller open.!
stateSwitch
"Open a window with a TriStateSwitchView on my state."
"TriStateButtonExample stateSwitch"
| model switch topView |
model _ self new.
switch _ TriStateButtonView on: model
aspect: #stateSwitchState
label: 'State'
click: #stateSwitchClick
press: #stateSwitchPress.
(topView _ StandardSystemView new)
model: model;
minimumSize: 100@50;
borderWidth: 1;
addSubView: switch.
topView controller open.!
thisAndThatSwitch
"Open a window with a TriStateSwitchView on my this and that."
"TriStateButtonExample thisAndThatSwitch"
| model switch topView |
model _ self new.
switch _ TriStateButtonView on: model
aspect: #thisAndThatSwitchState
label: 'This & That'
click: #thisAndThatSwitchClick
press: #thisAndThatSwitchPress.
(topView _ StandardSystemView new)
model: model;
minimumSize: 100@50;
borderWidth: 1;
addSubView: switch.
topView controller open.! !